//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package roadmap_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/roadmap_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/roadmap_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

type RoadmapApiImpl struct {
	roadmap_api.UnimplementedRoadmapApiServer
}

func (apiImpl *RoadmapApiImpl) Create(ctx context.Context, req *roadmap_api.CreateRequest) (*roadmap_api.CreateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_api.CreateResponse{
			Code:   roadmap_api.CreateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	roadmapId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		dbItem := &roadmap_dao.RoadmapInfoDbItem{
			RoadmapId: roadmapId,
			BasicInfo: roadmap_dao.BasicRoadmapInfoDbItem{
				Title: req.BasicInfo.Title,
				Desc:  req.BasicInfo.Desc,
			},
			OwnerType:   uint32(roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER),
			PubState:    false,
			HotValue:    0,
			OwnerUserId: sessionItem.UserId,
			TagList:     []string{},
			CreateTime:  nowTime,
			UpdateTime:  nowTime,
		}
		err = roadmap_dao.RoadmapInfoDao.Insert(sessCtx, dbItem)
		if err != nil {
			return nil, err
		}
		return &roadmap_api.CreateResponse{
			Code:      roadmap_api.CreateResponse_CODE_OK,
			RoadmapId: roadmapId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_api.CreateResponse), nil
}

func (apiImpl *RoadmapApiImpl) ListPub(ctx context.Context, req *roadmap_api.ListPubRequest) (*roadmap_api.ListPubResponse, error) {
	emptyList := []*roadmap_api.RoadmapInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		if req.SessionId != "" {
			return &roadmap_api.ListPubResponse{
				Code:        roadmap_api.ListPubResponse_CODE_WRONG_SESSION,
				ErrMsg:      "会话不存在",
				RoadmapList: emptyList,
			}, nil
		} else {
			//未登录用户也能查看路线图
			sessionItem = &dao.SessionDbItem{}
		}
	}
	listParam := &roadmap_api.ListParam{
		FilterByOwner:       false,
		OwnerType:           roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN,
		FilterByOwnerUserId: false,
		OwnerUserId:         "",
		FilterByKeyword:     req.FilterByKeyword,
		Keyword:             req.Keyword,
		FilterByTag:         req.FilterByTag,
		Tag:                 req.Tag,
	}
	count, err := roadmap_dao.RoadmapInfoDao.Count(ctx, listParam, true, true)
	if err != nil {
		return nil, err
	}
	roadmapItemList, err := roadmap_dao.RoadmapInfoDao.List(ctx, listParam, true, true, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}
	//获取用户信息
	userIdList := []string{}
	for _, roadmapItem := range roadmapItemList {
		if roadmapItem.OwnerType == uint32(roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER) {
			userIdList = append(userIdList, roadmapItem.OwnerUserId)
		}
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//是否是白名单用户
	isWhiteUser, err := roadmap_dao.WhiteUserDao.Exist(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	//生成结果
	infoList := []*roadmap_api.RoadmapInfo{}
	for _, roadmapItem := range roadmapItemList {
		userPerm := apiImpl.calcUserPerm(roadmapItem, sessionItem.UserId, isWhiteUser)
		info := roadmapItem.ToRoadmapInfo(userPerm)
		if roadmapItem.OwnerType == uint32(roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN) {
			info.OwnerUserId = ""
		} else {
			userItem, ok := userItemMap[roadmapItem.OwnerUserId]
			if ok {
				info.OwnerDisplayName = userItem.BasicInfo.DisplayName
				info.OwnerLogoUri = userItem.BasicInfo.LogoUri
			}
		}
		infoList = append(infoList, info)
	}

	return &roadmap_api.ListPubResponse{
		Code:        roadmap_api.ListPubResponse_CODE_OK,
		TotalCount:  count,
		RoadmapList: infoList,
	}, nil
}

func (apiImpl *RoadmapApiImpl) ListMy(ctx context.Context, req *roadmap_api.ListMyRequest) (*roadmap_api.ListMyResponse, error) {
	emptyList := []*roadmap_api.RoadmapInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_api.ListMyResponse{
			Code:        roadmap_api.ListMyResponse_CODE_WRONG_SESSION,
			ErrMsg:      "会话不存在",
			RoadmapList: emptyList,
		}, nil
	}
	listParam := &roadmap_api.ListParam{
		FilterByOwner:       true,
		OwnerType:           roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER,
		FilterByOwnerUserId: true,
		OwnerUserId:         sessionItem.UserId,
		FilterByKeyword:     req.FilterByKeyword,
		Keyword:             req.Keyword,
		FilterByTag:         req.FilterByTag,
		Tag:                 req.Tag,
	}
	count, err := roadmap_dao.RoadmapInfoDao.Count(ctx, listParam, false, false)
	if err != nil {
		return nil, err
	}
	roadmapItemList, err := roadmap_dao.RoadmapInfoDao.List(ctx, listParam, false, false, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}

	//是否是白名单用户
	isWhiteUser, err := roadmap_dao.WhiteUserDao.Exist(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}

	//生成结果
	infoList := []*roadmap_api.RoadmapInfo{}
	for _, roadmapItem := range roadmapItemList {
		userPerm := apiImpl.calcUserPerm(roadmapItem, sessionItem.UserId, isWhiteUser)
		info := roadmapItem.ToRoadmapInfo(userPerm)
		info.OwnerDisplayName = sessionItem.DisplayName
		info.OwnerLogoUri = sessionItem.LogoUri
		infoList = append(infoList, info)
	}

	return &roadmap_api.ListMyResponse{
		Code:        roadmap_api.ListMyResponse_CODE_OK,
		TotalCount:  count,
		RoadmapList: infoList,
	}, nil
}

func (apiImpl *RoadmapApiImpl) Get(ctx context.Context, req *roadmap_api.GetRequest) (*roadmap_api.GetResponse, error) {
	emptyInfo := &roadmap_api.RoadmapInfo{
		BasicInfo: &roadmap_api.BasicRoadmapInfo{},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_api.GetResponse{
			Code:    roadmap_api.GetResponse_CODE_WRONG_SESSION,
			ErrMsg:  "会话不存在",
			Roadmap: emptyInfo,
		}, nil
	}

	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_api.GetResponse{
			Code:    roadmap_api.GetResponse_CODE_NO_ROADMAP,
			ErrMsg:  "路线图不存在",
			Roadmap: emptyInfo,
		}, nil
	}
	//只能访问自己和公开的
	if !(roadmapItem.OwnerUserId == sessionItem.UserId || roadmapItem.PubState) {
		return &roadmap_api.GetResponse{
			Code:    roadmap_api.GetResponse_CODE_NO_PERMISSION,
			ErrMsg:  "没有权限",
			Roadmap: emptyInfo,
		}, nil
	}

	//获取用户信息
	userIdList := []string{}
	if roadmapItem.OwnerType == uint32(roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER) {
		userIdList = append(userIdList, roadmapItem.OwnerUserId)
	}

	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	//是否是白名单用户
	isWhiteUser, err := roadmap_dao.WhiteUserDao.Exist(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}

	//生成结果
	userPerm := apiImpl.calcUserPerm(roadmapItem, sessionItem.UserId, isWhiteUser)
	info := roadmapItem.ToRoadmapInfo(userPerm)
	if roadmapItem.OwnerType == uint32(roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN) {
		info.OwnerUserId = ""
	} else {
		userItem, ok := userItemMap[roadmapItem.OwnerUserId]
		if ok {
			info.OwnerDisplayName = userItem.BasicInfo.DisplayName
			info.OwnerLogoUri = userItem.BasicInfo.LogoUri
		}
	}
	return &roadmap_api.GetResponse{
		Code:    roadmap_api.GetResponse_CODE_OK,
		Roadmap: info,
	}, nil
}

func (apiImpl *RoadmapApiImpl) Update(ctx context.Context, req *roadmap_api.UpdateRequest) (*roadmap_api.UpdateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_api.UpdateResponse{
			Code:   roadmap_api.UpdateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_api.UpdateResponse{
			Code:   roadmap_api.UpdateResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}

	userPerm := apiImpl.calcUserPerm(roadmapItem, sessionItem.UserId, false)
	if !userPerm.CanUpdateContent {
		return &roadmap_api.UpdateResponse{
			Code:   roadmap_api.UpdateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = roadmap_dao.RoadmapInfoDao.UpdateBasicInfo(sessCtx, req.RoadmapId, &roadmap_dao.BasicRoadmapInfoDbItem{
			Title: req.BasicInfo.Title,
			Desc:  req.BasicInfo.Desc,
		}, nowTime)
		if err != nil {
			return nil, err
		}
		return &roadmap_api.UpdateResponse{
			Code: roadmap_api.UpdateResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_api.UpdateResponse), nil
}

func (apiImpl *RoadmapApiImpl) UpdatePubState(ctx context.Context, req *roadmap_api.UpdatePubStateRequest) (*roadmap_api.UpdatePubStateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_api.UpdatePubStateResponse{
			Code:   roadmap_api.UpdatePubStateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_api.UpdatePubStateResponse{
			Code:   roadmap_api.UpdatePubStateResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}
	if roadmapItem.TagList == nil {
		roadmapItem.TagList = []string{}
	}

	if roadmapItem.PubState == req.PubState {
		return &roadmap_api.UpdatePubStateResponse{
			Code: roadmap_api.UpdatePubStateResponse_CODE_OK,
		}, nil
	}

	//是否是白名单用户
	isWhiteUser, err := roadmap_dao.WhiteUserDao.Exist(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}

	userPerm := apiImpl.calcUserPerm(roadmapItem, sessionItem.UserId, isWhiteUser)
	if !userPerm.CanUpdateContent {
		return &roadmap_api.UpdatePubStateResponse{
			Code:   roadmap_api.UpdatePubStateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = roadmap_dao.RoadmapInfoDao.UpdatePubState(sessCtx, req.RoadmapId, req.PubState)
		if err != nil {
			return nil, err
		}
		if req.PubState {
			whiteUserItem, err := roadmap_dao.WhiteUserDao.Get(sessCtx, sessionItem.UserId)
			if err != nil {
				return nil, err
			}
			includeTag := false
			for _, tag := range roadmapItem.TagList {
				if tag == whiteUserItem.DefaultTag {
					includeTag = true
				}
			}
			if !includeTag {
				roadmapItem.TagList = append(roadmapItem.TagList, whiteUserItem.DefaultTag)
				err = roadmap_dao.RoadmapInfoDao.UpdateTagList(sessCtx, req.RoadmapId, roadmapItem.TagList)
				if err != nil {
					return nil, err
				}
			}
		}
		return &roadmap_api.UpdatePubStateResponse{
			Code: roadmap_api.UpdatePubStateResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_api.UpdatePubStateResponse), nil
}

func (apiImpl *RoadmapApiImpl) Remove(ctx context.Context, req *roadmap_api.RemoveRequest) (*roadmap_api.RemoveResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &roadmap_api.RemoveResponse{
			Code:   roadmap_api.RemoveResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_api.RemoveResponse{
			Code: roadmap_api.RemoveResponse_CODE_OK,
		}, nil
	}
	userPerm := apiImpl.calcUserPerm(roadmapItem, sessionItem.UserId, false)
	if !userPerm.CanRemove {
		return &roadmap_api.RemoveResponse{
			Code:   roadmap_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = roadmap_dao.RoadmapInfoDao.Remove(sessCtx, req.RoadmapId)
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.NodeDao.RemoveByRoadmap(sessCtx, req.RoadmapId)
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.EdgeDao.RemoveByRoadmap(sessCtx, req.RoadmapId)
		if err != nil {
			return nil, err
		}
		//清除用户访问记录
		err = roadmap_dao.AccessRecordDao.RemoveByRoadmap(sessCtx, req.RoadmapId)
		if err != nil {
			return nil, err
		}
		//清除节点状态
		err = roadmap_dao.StateDao.RemoveByRoadmap(sessCtx, req.RoadmapId)
		if err != nil {
			return nil, err
		}
		return &roadmap_api.RemoveResponse{
			Code: roadmap_api.RemoveResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_api.RemoveResponse), nil
}

func (apiImpl *RoadmapApiImpl) calcUserPerm(roadmapItem *roadmap_dao.RoadmapInfoDbItem, ownerUserId string, isWhiteUser bool) *roadmap_api.UserPerm {
	userPerm := &roadmap_api.UserPerm{}
	if ownerUserId == roadmapItem.OwnerUserId {
		userPerm.CanUpdateContent = true
		userPerm.CanRemove = true
		userPerm.CanUpdatePubState = isWhiteUser
	}
	if roadmapItem.PubState {
		userPerm.CanRemove = false
	}
	return userPerm
}
